#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#include <windows.h>
#define NaN 1e100;
using namespace std;

class Matrix
{
	public:
		int *seq,*copy;
		bool *check;
		double val;
		vector<vector<double>> m,adj,cof;
		int Reverse(int *p,int l,int r);
		double Calculate(vector<vector<double>> X,int depth);
		double Determinat();
		void Print(vector<vector<double>> X);
		void Read();
		vector<vector<double>> Cofactor(vector<vector<double>> X,int row,int col);
		Matrix operator + (const Matrix &X);
		Matrix operator - (const Matrix &X);
		Matrix operator * (const Matrix &X);
		Matrix operator * (const double &X);
		Matrix operator ~ ();
};

map<string,Matrix> library;
map<string,Matrix>::iterator it;

int Matrix::Reverse(int *p,int l,int r)
{
	int i=l,j=(l+r)/2+1,*temp=new int[r-l+1],now=0,res;
	if(r==l) return 0;
	res=Reverse(p,l,(l+r)/2)+Reverse(p,(l+r)/2+1,r);
	while(i!=(l+r)/2+1&&j!=r+1)
	{
		while(p[i]>p[j]&&i!=(l+r)/2+1) temp[now++]=p[i++],res++;
		while(p[j]>p[i]&&j!=r+1) temp[now++]=p[j++];
	}
	while(i!=(l+r)/2+1) temp[now++]=p[i++];
	while(j!=r+1) temp[now++]=p[j++];
	for(i=l;i<=r;i++) p[i]=temp[i-l];
	free(temp);
	return res;
}
		
double Matrix::Calculate(vector<vector<double>> X,int depth)
{
	int i;
	double res=0;
	if(depth==X.size())
	{
		double temp=1;
		for(i=0;i<X.size();i++) temp*=X[i][copy[i]=seq[i]];
		return temp*(Reverse(copy,0,X.size()-1)%2?-1:1); 
	}
	for(i=0;i<X.size();i++) if(!check[i])
	{
		check[i]=true;
		seq[depth]=i;
		res+=Calculate(X,depth+1);
		check[i]=false;
	}
	return res;
}

double Matrix::Determinat()
{
	return val;
}

void Matrix::Print(vector<vector<double>> X)
{
	int i,j;
	printf("\n");
	for(i=0;i<X.size();i++)
	{
		for(j=0;j<X[i].size();j++) cout<<X[i][j]<<'\t';
		printf("\n\n");
	}
}

void Matrix::Read()
{
	int i,j,k,row,col;
	string name;
	cin>>name;
	while(library.find(name)!=library.end()) 
	{
		MessageBox(0,"This name has been occupied! Please change another one.","SYSTEM",MB_OK);
		printf("def ");
		cin>>name;
	}
	printf("Please input the number of row and column respectively, separated by space:\n");
	scanf("%d%d",&row,&col);
	printf("Please input the elements of the matrix:\n");
	m.resize(row);
	for(i=0;i<row;i++)
	{
		m[i].resize(col);
		for(j=0;j<col;j++) scanf("%lf",&m[i][j]);
	}
	if(row==col) 
	{
		check=new bool[row];
		memset(check,0,sizeof(check));
		seq=new int[row];
		copy=new int[row];
		val=Calculate(m,0);
		adj.resize(row);
		for(i=0;i<row;i++)
		{
			adj[i].resize(col);
			memset(check,0,sizeof(check));
			for(j=0;j<col;j++) adj[i][j]=((i+j)%2?-1:1)*Calculate(Cofactor(m,j,i),0);
		}
		free(check);
		free(seq);
		free(copy);
	}
	else val=NaN;
	library[name]=*this;
	printf("Matrix '%s' has been created successfully\n\n",name.c_str());
}

vector<vector<double>> Matrix::Cofactor(vector<vector<double>> X,int row,int col)
{
	int i,j;
	vector<double> temp1;
	vector<vector<double>> temp2;
	for(i=0;i<X.size();i++) if(i!=row)
	{
		temp1.clear();
		for(j=0;j<X[0].size();j++) if(j!=col) temp1.push_back(X[i][j]);
		temp2.push_back(temp1);
	}
	temp2.resize(X.size()-1);
	for(i=0;i<temp2.size();i++) temp2[i].resize(X[0].size()-1);
	return temp2;
}

Matrix Matrix::operator + (const Matrix &X)
{
	int i,j;
	Matrix temp;
	temp.m.resize(m.size());
	for(i=0;i<temp.m.size();i++) 
	{
		temp.m[i].resize(m[i].size());
		for(j=0;j<temp.m[i].size();j++) temp.m[i][j]=m[i][j]+X.m[i][j];
	}
	return temp;
}

Matrix Matrix::operator - (const Matrix &X)
{
	int i,j;
	Matrix temp;
	temp.m.resize(m.size());
	for(i=0;i<temp.m.size();i++) 
	{
		temp.m[i].resize(m[i].size());
		for(j=0;j<temp.m[i].size();j++) temp.m[i][j]=m[i][j]-X.m[i][j];
	}
	return temp;
}

Matrix Matrix::operator * (const Matrix &X)
{
	int i,j,k;
	Matrix temp;
	temp.m.resize(m.size());
	for(i=0;i<temp.m.size();i++) 
	{
		temp.m[i].resize(X.m[i].size());
		for(j=0;j<temp.m[i].size();j++) for(k=0;k<m[i].size();k++) temp.m[i][j]+=m[i][k]*X.m[k][j];
	}
	return temp;
}

Matrix Matrix::operator * (const double &X)
{
	int i,j;
	Matrix temp;
	temp.m.resize(m.size());
	temp.adj.resize(adj.size());
	for(i=0;i<temp.m.size();i++) 
	{
		temp.m[i].resize(m[i].size()); 
		temp.adj[i].resize(adj[i].size());
		for(j=0;j<temp.m[i].size();j++) temp.m[i][j]=m[i][j]*X,temp.adj[i][j]=adj[i][j]*X;
	}
	return temp;
}

Matrix Matrix::operator ~ ()
{
	int i,j;
	Matrix temp;
	temp.m.resize(m[0].size());
	for(i=0;i<temp.m.size();i++)
	{
		temp.m[i].resize(m.size());
		for(j=0;j<temp.m[i].size();j++) temp.m[i][j]=m[j][i];
	}
	return temp;
}

int main()
{
	double num;
	string cmd,name1,name2,equation;
	Matrix M,X1,X2;
	while(cin>>cmd&&cmd!="quit")
	{
		if(cmd=="?")
		{
			printf("\ndef A-------------------To define a matrix with name A.\n");
			printf("show A-----------------------------To display A matrix.\n");
			printf("del A-------------------------------To delete A matrix.\n");
			printf("+ A B-----------To calculate the sum of matrix A and B.\n");
			printf("- A B----------------To calculate the matrix A minus B.\n");
			printf("* A B-------To calculate the product of matrix A and B.\n");
			printf(" N A-----To calculate matrix A multiplied by number N.\n");
			printf("det A----------To calculate the determinat of matrix A.\n");
			printf("inv A-------------To calculate the inverse matrix of A.\n");
			printf("tran A----------To calculate the transpose matrix of A.\n");
			printf("adj A-------------To calculate the adjoint matrix of A.\n");
			printf("cls---------------Clean up the external terminal texts.\n");
			printf("list--------------------To show all the matrix defined.\n");
			printf("quit------------------------Quit the Matrix calculator.\n\n");
		}
		else if(cmd=="def") 
		{
			M.Read();
		}
		else if(cmd=="cls")
		{
			system("cls");
		}
		else if(cmd=="show")
		{
			cin>>name1;
			if(library.find(name1)!=library.end()) 
			{
				X1=library[name1];
				X1.Print(X1.m);
			}
			else 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
			}
		}
		else if(cmd=="del")
		{
			cin>>name1;
			if(library.find(name1)!=library.end()) 
			{
				library.erase(library.find(name1));
				printf("Matrix '%s' has been removed successfully!\n\n",name1.c_str());
			}
			else
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
			}
		}
		else if(cmd=="+")
		{
			cin>>name1>>name2;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding former matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			if(library.find(name2)==library.end())
			{
				MessageBox(0,"No corresponding latter matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			X1=library[name1],X2=library[name2];
			if((X1.m.size()!=X2.m.size())||(X1.m[0].size()!=X2.m[0].size())) 
			{
				MessageBox(0,"They do not have same size!","SYSTEM",MB_OK);
				printf("\n");
				continue;	
			}
			M=(X1+X2);
			M.Print(M.m);
		}
		else if(cmd=="-")
		{
			cin>>name1>>name2;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding former matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			if(library.find(name2)==library.end())
			{
				MessageBox(0,"No corresponding latter matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			X1=library[name1],X2=library[name2];
			if((X1.m.size()!=X2.m.size())||(X1.m[0].size()!=X2.m[0].size())) 
			{
				MessageBox(0,"They do not have same size!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
		    M=X1-X2;
			M.Print(M.m);
		}
		else if(cmd=="*")
		{
			cin>>name1>>name2;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding former matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			if(library.find(name2)==library.end())
			{
				MessageBox(0,"No corresponding latter matrix found, please check your input!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}	
			X1=library[name1],X2=library[name2];
			if(X1.m[0].size()!=X2.m.size()) 
			{
				MessageBox(0,"They can not multiply with each other!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			M=X1*X2;
			M.Print(M.m);
		}
		else if(cmd=="")
		{
			cin>>num>>name1;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			M=library[name1]*num;
			M.Print(M.m);
		}
		else if(cmd=="inv")
		{
			cin>>name1;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			X1=library[name1];
			if(X1.m.size()!=X1.m[0].size())
			{
				MessageBox(0,"It is not a square matrix!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			if(!X1.Determinat())
			{
				MessageBox(0,"Its determinat equals 0!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			X1=X1*(1.0/X1.Determinat());
			X1.Print(X1.adj);
		}
		else if(cmd=="tran")
		{
			cin>>name1;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			X1=library[name1];
			X1=~X1;
			X1.Print(X1.m);
		}
		else if(cmd=="det")
		{
			cin>>name1;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			X1=library[name1];
			if(X1.m.size()!=X1.m[0].size())
			{
				MessageBox(0,"It is not a square matrix!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			cout<<'='<<library[name1].Determinat()<<"\n\n";
		}
		else if(cmd=="adj")
		{
			cin>>name1;
			if(library.find(name1)==library.end()) 
			{
				MessageBox(0,"No corresponding matrix found, please check your input!","SYSTEM",MB_OK);	
				printf("\n");
				continue;
			}
			X1=library[name1];
			if(X1.m.size()!=X1.m[0].size())
			{
				MessageBox(0,"It is not a square matrix!","SYSTEM",MB_OK);
				printf("\n");
				continue;
			}
			X1.Print(X1.adj);
		}
		else if(cmd=="list")
		{
			printf("\n");
			for(it=library.begin();it!=library.end();it++) printf("%s\n",it->first.c_str());
			printf("\n");
		}
		else 
		{
			MessageBox(0,"Unknown command! Please input '?' for help.","SYSTEM",MB_OK);
			printf("\n");
		}
	}
	return 0;
}
